import { exec } from 'child_process';
import { promisify } from 'util';
import fs from 'fs-extra';
import path from 'path';
import { fileURLToPath } from 'url';

const execAsync = promisify(exec);
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

// 获取命令行参数
const environment = 'dev-local'; // 指定为 dev-local 环境
console.log(`\x1b[34m[配置]\x1b[0m 部署环境: ${environment}`);

// 配置信息
const config = {
    buildCommand: 'npm run build:dev-local', // 使用dev-local构建命令
    distPath: 'dist',
    deployRepo: 'https://github.com/viridian-carbon/viridian-frontend.git',
    deployBranch: 'dev-local', // 部署到dev-local分支
    tempPath: '.deploy_temp',
    commitMessage: `chore: update dev-local dist files`
};

console.log('\x1b[34m[配置]\x1b[0m 部署配置信息:', {
    '构建命令': config.buildCommand,
    '目标分支': config.deployBranch,
    '临时目录': config.tempPath
});

/**
 * 执行命令并返回结果
 * @param {string} command - 要执行的命令
 * @param {string} cwd - 当前工作目录
 * @returns {Promise<string>} - 命令的标准输出
 */
async function executeCommand(command, cwd = process.cwd()) {
    console.log(`\x1b[36m[执行]\x1b[0m 运行命令: ${command}`);
    try {
        const { stdout, stderr } = await execAsync(command, { cwd });
        if (stderr) console.log('\x1b[33m[警告]\x1b[0m 命令输出:', stderr);
        return stdout.trim();
    } catch (error) {
        console.error('\x1b[31m[错误]\x1b[0m 命令执行失败:', error.message);
        throw error;
    }
}

/**
 * 检查指定目录是否有文件更改
 * @param {string} dir - 要检查的目录
 * @returns {Promise<boolean>} - 是否有更改
 */
async function hasChanges(dir) {
    try {
        const status = await executeCommand('git status --porcelain', dir);
        return status.length > 0;
    } catch (error) {
        console.error('\x1b[31m[错误]\x1b[0m 检查文件更改状态失败:', error);
        return false;
    }
}

/**
 * 初始化部署仓库
 */
async function initRepo() {
    console.log(`\x1b[34m[初始化]\x1b[0m 初始化部署仓库 (${config.deployBranch}分支)...`);
    await fs.ensureDir(config.tempPath);
    await fs.emptyDir(config.tempPath);

    const readmePath = path.join(process.cwd(), config.tempPath, 'README.md');
    await fs.writeFile(readmePath, `# Dist Repository\n\nThis repository contains built files for ${environment} environment.`);

    const tempDir = path.join(process.cwd(), config.tempPath);

    try {
        await executeCommand('git init', tempDir);
        await executeCommand('git config user.name "Deploy Bot"', tempDir);
        await executeCommand('git config user.email "deploy@example.com"', tempDir);

        try {
            await executeCommand('git remote remove origin', tempDir);
        } catch (error) {
            console.log('\x1b[33m[警告]\x1b[0m 无需移除远程仓库');
        }

        await executeCommand(`git remote add origin ${config.deployRepo}`, tempDir);
        await executeCommand(`git checkout -b ${config.deployBranch}`, tempDir);
        await executeCommand('git add README.md', tempDir);
        await executeCommand('git commit -m "init: initialize repository"', tempDir);
    } catch (error) {
        console.error('\x1b[31m[错误]\x1b[0m 初始化仓库失败:', error);
        throw error;
    }
}

/**
 * 调整版本号的奇偶性
 * @param {string} version - 原始版本号
 * @param {string} environment - 环境（dev-local）
 * @returns {string} - 调整后的版本号
 */
function adjustVersion(version, environment) {
    console.log(`\x1b[34m[版本]\x1b[0m 调整版本号, 当前版本: ${version}, 环境: ${environment}`);
    const versionParts = version.split('.').map(Number);
    if (versionParts.length !== 3 || versionParts.some(isNaN)) {
        throw new Error(`无效的版本号格式: ${version}`);
    }

    let [major, minor, patch] = versionParts;

    // dev-local环境使用奇数版本号，与dev环境保持一致
    if (patch % 2 === 0) patch += 1;

    const newVersion = `${major}.${minor}.${patch}-local`;
    console.log(`\x1b[34m[版本]\x1b[0m 调整后的版本号: ${newVersion}`);
    return newVersion;
}

/**
 * 更新 VERSION 文件，并与远程版本比较
 * @param {string|null} remoteVersion - 远程仓库中的版本号
 */
async function updateVersionFile(remoteVersion) {
    try {
        const packageJsonPath = path.join(process.cwd(), 'package.json');
        const packageJson = await fs.readJSON(packageJsonPath);
        const originalVersion = packageJson.version;

        console.log(`\x1b[34m[版本]\x1b[0m 原始版本号: ${originalVersion}`);
        if (remoteVersion) {
            console.log(`\x1b[34m[版本]\x1b[0m 远程版本号: ${remoteVersion}`);
        }

        const newVersion = adjustVersion(originalVersion, environment);

        if (remoteVersion && newVersion === remoteVersion) {
            throw new Error(`新版本号 (${newVersion}) 与远程仓库已有版本号 (${remoteVersion}) 相同，无法满足版本升级要求。`);
        }

        const versionFilePath = path.join(process.cwd(), config.distPath, 'VERSION');
        await fs.writeFile(versionFilePath, newVersion, 'utf8');
        console.log(`\x1b[32m[成功]\x1b[0m 写入 VERSION 文件: ${newVersion}`);
    } catch (error) {
        console.error('\x1b[31m[错误]\x1b[0m 更新 VERSION 文件失败:', error.message);
        throw error;
    }
}

/**
 * 部署函数
 */
async function deploy() {
    try {
        console.log('\x1b[34m[部署]\x1b[0m 开始部署流程...');
        console.log(`\x1b[34m[部署]\x1b[0m 目标分支: ${config.deployBranch}`);

        // 1. 执行项目打包
        console.log(`\x1b[34m[构建]\x1b[0m 开始打包项目 (${environment}环境)...`);
        await executeCommand(config.buildCommand);
        console.log('\x1b[32m[构建]\x1b[0m 项目打包完成');

        // 2. 准备部署目录
        console.log('\x1b[34m[准备]\x1b[0m 准备部署目录...');
        let remoteVersion = null;
        try {
            await fs.remove(config.tempPath);
            await executeCommand(`git clone ${config.deployRepo} ${config.tempPath} --depth 1 -b ${config.deployBranch}`);
            console.log('\x1b[32m[成功]\x1b[0m 成功克隆远程仓库');

            const tempDir = path.join(process.cwd(), config.tempPath);
            await executeCommand('git config user.name "Deploy Bot"', tempDir);
            await executeCommand('git config user.email "deploy@example.com"', tempDir);

            // 读取远程仓库中的 VERSION 文件
            const remoteVersionPath = path.join(process.cwd(), config.tempPath, 'VERSION');
            if (await fs.pathExists(remoteVersionPath)) {
                remoteVersion = (await fs.readFile(remoteVersionPath, 'utf8')).trim();
                console.log(`\x1b[34m[版本]\x1b[0m 检测到远程版本: ${remoteVersion}`);
            } else {
                console.log('\x1b[33m[警告]\x1b[0m 远程仓库中没有 VERSION 文件，将视为首次部署');
            }
        } catch (error) {
            console.log('\x1b[33m[警告]\x1b[0m 远程仓库不存在或分支不存在，创建新的仓库...');
            await initRepo();
            remoteVersion = null;
        }

        // 3. 保存原有的 .github 和 deploy 文件夹
        console.log('\x1b[34m[配置]\x1b[0m 处理配置文件夹...');
        const tempPath = path.join(process.cwd(), config.tempPath);
        const tempGithubPath = path.join(tempPath, '.github');
        const tempDeployPath = path.join(tempPath, 'deploy');
        let hasExistingFolders = {
            github: false,
            deploy: false
        };

        // 检查并备份远程仓库中的文件夹
        if (await fs.pathExists(tempGithubPath)) {
            console.log('\x1b[34m[备份]\x1b[0m 备份远程仓库的 .github 文件夹');
            await fs.copy(tempGithubPath, path.join(process.cwd(), '.github_backup'));
            hasExistingFolders.github = true;
        }
        if (await fs.pathExists(tempDeployPath)) {
            console.log('\x1b[34m[备份]\x1b[0m 备份远程仓库的 deploy 文件夹');
            await fs.copy(tempDeployPath, path.join(process.cwd(), 'deploy_backup'));
            hasExistingFolders.deploy = true;
        }

        // 4. 更新 VERSION 文件
        await updateVersionFile(remoteVersion);

        // 5. 清空部署仓库中的旧文件（保留 .git 目录）
        console.log('\x1b[34m[清理]\x1b[0m 清理部署目录...');
        const files = await fs.readdir(tempPath);
        for (const file of files) {
            if (file !== '.git') {
                await fs.remove(path.join(tempPath, file));
            }
        }

        // 6. 复制新的打包文件到部署目录
        console.log('\x1b[34m[复制]\x1b[0m 复制新的构建文件到部署目录...');
        await fs.copy(config.distPath, config.tempPath);

        // 7. 处理 .github 和 deploy 文件夹
        const projectGithubPackgePath = path.join(process.cwd(), 'githubPackge');

        // 处理 .github 文件夹
        if (hasExistingFolders.github) {
            console.log('\x1b[34m[恢复]\x1b[0m 恢复远程仓库的 .github 文件夹');
            await fs.copy(path.join(process.cwd(), '.github_backup'), tempGithubPath);
        } else {
            console.log('\x1b[34m[复制]\x1b[0m 从项目复制 .github 文件夹');
            const sourceGithubPath = path.join(projectGithubPackgePath, '.github');
            if (await fs.pathExists(sourceGithubPath)) {
                await fs.copy(sourceGithubPath, path.join(tempPath, '.github'));
                console.log('\x1b[32m[成功]\x1b[0m .github 文件夹复制完成');
            } else {
                console.warn('\x1b[33m[警告]\x1b[0m 未找到 .github 文件夹');
            }
        }

        // 处理 deploy 文件夹
        if (hasExistingFolders.deploy) {
            console.log('\x1b[34m[恢复]\x1b[0m 恢复远程仓库的 deploy 文件夹');
            await fs.copy(path.join(process.cwd(), 'deploy_backup'), tempDeployPath);
        } else {
            console.log('\x1b[34m[复制]\x1b[0m 从项目复制 deploy 文件夹');
            const sourceDeployPath = path.join(projectGithubPackgePath, 'deploy');
            if (await fs.pathExists(sourceDeployPath)) {
                await fs.copy(sourceDeployPath, path.join(tempPath, 'deploy'));
                console.log('\x1b[32m[成功]\x1b[0m deploy 文件夹复制完成');
            } else {
                console.warn('\x1b[33m[警告]\x1b[0m 未找到 deploy 文件夹');
            }
        }

        // 8. 清理备份文件
        console.log('\x1b[34m[清理]\x1b[0m 清理备份文件...');
        await fs.remove(path.join(process.cwd(), '.github_backup'));
        await fs.remove(path.join(process.cwd(), 'deploy_backup'));

        // 9. Git 操作
        console.log('\x1b[34m[Git]\x1b[0m 准备提交变更...');
        const tempDir = path.join(process.cwd(), config.tempPath);
        await executeCommand('git add -A', tempDir);

        if (await hasChanges(tempDir)) {
            console.log('\x1b[34m[Git]\x1b[0m 检测到文件变更，提交变更...');
            await executeCommand(`git commit -m "${config.commitMessage}"`, tempDir);
            console.log(`\x1b[34m[Git]\x1b[0m 推送到远程仓库 ${config.deployBranch} 分支...`);
            await executeCommand(`git push -f origin ${config.deployBranch}`, tempDir);
            console.log('\x1b[32m[Git]\x1b[0m 推送完成');
        } else {
            console.log('\x1b[33m[Git]\x1b[0m 没有检测到文件变更，跳过提交');
        }

        // 10. 清理临时目录
        console.log('\x1b[34m[清理]\x1b[0m 清理临时文件...');
        await fs.remove(config.tempPath);

        console.log('\x1b[32m[完成]\x1b[0m 部署完成!');
        console.log(`\x1b[32m[完成]\x1b[0m 可访问仓库查看更新: ${config.deployRepo} (${config.deployBranch} 分支)`);

    } catch (error) {
        console.error('\x1b[31m[错误]\x1b[0m 部署失败:', error.message);
        // 清理所有临时文件
        try {
            await fs.remove(path.join(process.cwd(), '.github_backup'));
            await fs.remove(path.join(process.cwd(), 'deploy_backup'));
            await fs.remove(config.tempPath);
        } catch (err) {
            console.error('\x1b[31m[错误]\x1b[0m 清理临时目录失败:', err.message);
        }
        process.exit(1);
    }
}

// 执行部署
await deploy();
// 部署完成后删除dist目录
await fs.remove(path.join(process.cwd(), 'dist'));